package com.hockeo.shared.rpc.command;

import java.util.HashMap;
import java.util.Map;

import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.hockeo.shared.VHUtil;

/**
 * Command dispatcher.
 *
 * @version $Id$
 * @author jjanke
 */
public class CommandDispatcher
{
  private final IRpcCommandServiceAsync     d_service;
  private final Map<ICommand<?>, IResponse> d_mapCache;

  /**
   * Creates a new command dispatcher.
   *
   * @param service the service to be used to execute commands
   */
  public CommandDispatcher( IRpcCommandServiceAsync service )
  {
    d_service = service;
    d_mapCache = new HashMap<ICommand<?>, IResponse>();
  }

  /**
   * Dispatches the given command directly.
   *
   * @param <S> the type of the dispatched command
   * @param <T> the type of the expected response
   * @param command the command to be dispatched
   * @param callback the callback that handles the command's response
   */
  @SuppressWarnings( "unchecked" )
  public <S extends ICommand<T>, T extends IResponse> void dispatch( S command, CommandCallback<T> callback )
  {
    d_service.execute( getSessionId(), command, (AsyncCallback<IResponse>) callback );
  }

  /**
   * Checks if the command has already been executed before and returns a cached response
   * if possible. If no cached response is available, the command is dispatched to the
   * underlying handler service.
   *
   * @param <S> the type of the dispatched command
   * @param <T> the type of the expected response
   * @param command the command to be dispatched
   * @param callback the callback that handles the command's response
   */
  @SuppressWarnings( "unchecked" )
  public <S extends ICommand<T>, T extends IResponse> void dispatchWithCache( final S command, final CommandCallback<T> callback )
  {
    T response = (T) d_mapCache.get( command );

    if ( response != null )
    {
      callback.onSuccess( response );
    }
    else
    {
      d_service.execute( getSessionId(), command, new CommandCallback<IResponse>() {
        @Override
        public void onFailure( Throwable t )
        {
          callback.onFailure( t );
        }

        @Override
        public void got( IResponse response )
        {
          d_mapCache.put( command, response );
          callback.onSuccess( (T) response );
        }
      } );
    }
  }

  /**
   * Returns the client side session id.
   */
  private String getSessionId()
  {
    return Cookies.getCookie( VHUtil.SESSION_COOKIE );
  }
}
